using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using MEA.AE_Data.Config;
using Peak.Can.Basic;

namespace MEA.AE_Data.Access
{
	public class ECU_Access : IECU_Access, IDisposable
	{
		public delegate void ECUAddConsoleHandler(string s, string AB);

		private bool rOpened_b;

		private bool stopRecThread_b;

		private string ab;

		private KWP2000 kwpECUA;

		private KWP2000 kwpECUB;

		private Queue rqu_ErrorsSync;

		private Queue rqu_Errors;

		private bool rbo_ReceiveQueue;

		private Hashtable rHashMessages_ht;

		private Queue rqu_Receive;

		private Queue rqu_ReceiveSync;

		private byte m_PcanHandle;

		private AutoResetEvent m_ReceiveEvent;

		private Thread m_ReadThread;

		private bool ecuAOnline;

		private bool ecuBOnline;

		private bool ECUReceiveConnected;

		public event ChangingHandler OnlineChangeECUA;

		public event ChangingHandler OnlineChangeECUB;

		public event ECUAddConsoleHandler ev_AddConsoleEvent;

		public ECU_Access()
		{
			rOpened_b = false;
			stopRecThread_b = false;
			ab = "";
			rqu_ErrorsSync = new Queue();
			rqu_Errors = Queue.Synchronized(rqu_ErrorsSync);
			rHashMessages_ht = new Hashtable(8);
			rqu_ReceiveSync = new Queue();
			rqu_Receive = Queue.Synchronized(rqu_ReceiveSync);
			m_PcanHandle = 81;
			kwpECUA = new KWP2000(AddMessage(new CANMessage(2016u, 0u, 0u, 8, 0u, "KWP2000_Send", 1)), AddMessage(new CANMessage(2024u, 0u, 0u, 8, 0u, "KWP2000_Receive", 1)));
			kwpECUB = new KWP2000(AddMessage(new CANMessage(2017u, 0u, 0u, 8, 0u, "KWP2000_Send", 1)), AddMessage(new CANMessage(2025u, 0u, 0u, 8, 0u, "KWP2000_Receive", 1)));
			m_ReceiveEvent = new AutoResetEvent(false);
		}

		private void waitForResponse(int waitCnt)
		{
			bool flag = false;
			int num = 0;
			while (!flag)
			{
				if (num >= waitCnt)
				{
					flag = true;
				}
			}
		}

		public List<byte> Query(ConfigData.e_ECUID ecuID, ConfigKWP.e_kwpServices serviceID, List<byte> sendList)
		{
			List<byte> data = new List<byte>(sendList.Count);
			KWP2000 kWP;
			bool flag;
			switch (ecuID)
			{
			case ConfigData.e_ECUID.A:
				kWP = kwpECUA;
				flag = ecuAOnline;
				break;
			case ConfigData.e_ECUID.B:
				kWP = kwpECUB;
				flag = ecuBOnline;
				break;
			default:
				throw new ECUSendErrorException();
			}
			lock (kWP)
			{
				if (!flag && serviceID != ConfigKWP.e_kwpServices.Communication_Start)
				{
					throw new ECUDisconnectedExeption();
				}
				data.AddRange(sendList);
				if (kWP.SendMessage(ref data) != ConfigBase.EOk.eSendOk)
				{
					throw new ECUSendErrorException();
				}
				if (!kWP.ev_Response.WaitOne(ConfigKWP.ResponseTime(serviceID)))
				{
					switch (ecuID)
					{
					case ConfigData.e_ECUID.A:
						if (this.OnlineChangeECUA != null)
						{
							this.OnlineChangeECUA(this, false);
						}
						ChangeOnlineStateECUA(false);
						break;
					case ConfigData.e_ECUID.B:
						if (this.OnlineChangeECUB != null)
						{
							this.OnlineChangeECUB(this, false);
						}
						ChangeOnlineStateECUB(false);
						break;
					}
					throw new ECUResponseTimeoutException();
				}
				if (kWP.AL_receive[0] == ConfigKWP.PositiveResponse(serviceID))
				{
					switch (ecuID)
					{
					case ConfigData.e_ECUID.A:
						switch (serviceID)
						{
						case ConfigKWP.e_kwpServices.Communication_Start:
							ChangeOnlineStateECUA(true);
							break;
						case ConfigKWP.e_kwpServices.Communication_Stop:
							ChangeOnlineStateECUA(false);
							break;
						}
						break;
					case ConfigData.e_ECUID.B:
						switch (serviceID)
						{
						case ConfigKWP.e_kwpServices.Communication_Start:
							ChangeOnlineStateECUB(true);
							break;
						case ConfigKWP.e_kwpServices.Communication_Stop:
							ChangeOnlineStateECUB(false);
							break;
						}
						break;
					}
					return kWP.AL_receive;
				}
				if (kWP.AL_receive[0] == ConfigKWP.NegativeResponse)
				{
					string text = "";
					switch (kWP.AL_receive[2])
					{
					case 16:
						text += "General reject ";
						break;
					case 17:
						text += "Service not suported ";
						break;
					case 18:
						text += "Subfunction not suported ";
						break;
					case 33:
						text += "Byssy, repeat request ";
						break;
					case 51:
						text += "Security access deniied ";
						break;
					case 53:
						text += "Invalid key ";
						break;
					}
					foreach (byte item in kWP.AL_receive)
					{
						text += string.Format("{0:X2} ", item);
					}
					if (this.ev_AddConsoleEvent != null)
					{
						this.ev_AddConsoleEvent("Response: " + text + "h", "            ");
					}
					if (kWP.AL_receive.Count > 0)
					{
						Console.WriteLine("NegResp = {0}!!!", kWP.AL_receive.ToString());
						throw new ECUResponseNegativeException(kWP.AL_receive[2].ToString());
					}
					throw new ECUResponseNegativeException("kwp.AL_receive empty");
				}
				string text2 = "AL_receive:";
				foreach (byte item2 in kWP.AL_receive)
				{
					text2 = text2 + string.Format("{0:X2}", item2) + " ";
				}
				if (this.ev_AddConsoleEvent != null)
				{
					this.ev_AddConsoleEvent("Response: " + text2 + "h", "            ");
				}
				throw new ECUResponseUnkownException(text2 + "h");
			}
		}

		public bool ConnectUSB()
		{
			if (!rOpened_b)
			{
				PCANBasic.LoadPCAN();
				if (PCANBasic.GetStatus(m_PcanHandle) != TPCANStatus.PCAN_ERROR_OK)
				{
					if (Init(500, 0))
					{
						rOpened_b = true;
					}
				}
				else
				{
					rOpened_b = true;
				}
				if (rOpened_b)
				{
					try
					{
						uint NumericBuffer = Convert.ToUInt32(m_ReceiveEvent.SafeWaitHandle.DangerousGetHandle().ToInt32());
						if (PCANBasic.SetValue(m_PcanHandle, TPCANParameter.PCAN_RECEIVE_EVENT, ref NumericBuffer, 4u) != TPCANStatus.PCAN_ERROR_OK)
						{
							rqu_Errors.Enqueue("CAN\tReceive event could not be initialized.");
							return false;
						}
						m_ReadThread = new Thread(CANReadThreadFunc);
						m_ReadThread.Name = "CANReadThreadFunc";
						m_ReadThread.Priority = ThreadPriority.Highest;
						m_ReadThread.IsBackground = true;
						m_ReadThread.Start();
					}
					catch
					{
						return false;
					}
				}
			}
			return rOpened_b;
		}

		private bool Init(short BaudRate, short XTD)
		{
			try
			{
				TPCANBaudrate btr0Btr = ((BaudRate >= 1000) ? TPCANBaudrate.PCAN_BAUD_1M : ((BaudRate >= 500) ? TPCANBaudrate.PCAN_BAUD_500K : ((BaudRate >= 250) ? TPCANBaudrate.PCAN_BAUD_250K : ((BaudRate >= 125) ? TPCANBaudrate.PCAN_BAUD_125K : ((BaudRate >= 100) ? TPCANBaudrate.PCAN_BAUD_100K : ((BaudRate >= 50) ? TPCANBaudrate.PCAN_BAUD_50K : ((BaudRate >= 20) ? TPCANBaudrate.PCAN_BAUD_20K : ((BaudRate < 10) ? TPCANBaudrate.PCAN_BAUD_5K : TPCANBaudrate.PCAN_BAUD_10K))))))));
				if (PCANBasic.Initialize(m_PcanHandle, btr0Btr) != TPCANStatus.PCAN_ERROR_OK)
				{
					rqu_Errors.Enqueue("CAN\tCannot open");
					return false;
				}
				if (((XTD != 0) ? PCANBasic.FilterMessages(m_PcanHandle, 0u, 536870911u, TPCANMode.PCAN_MODE_EXTENDED) : PCANBasic.FilterMessages(m_PcanHandle, 0u, 2047u, TPCANMode.PCAN_MODE_STANDARD)) != TPCANStatus.PCAN_ERROR_OK)
				{
					rqu_Errors.Enqueue("CAN\tCannot set filter");
					return false;
				}
				return true;
			}
			catch
			{
				rqu_Errors.Enqueue("CAN\tFailed to initialize");
				return false;
			}
		}

		private void ChangeOnlineStateECUA(bool online)
		{
			ecuAOnline = online;
			this.OnlineChangeECUA(this, online);
		}

		private void ChangeOnlineStateECUB(bool online)
		{
			ecuBOnline = online;
			this.OnlineChangeECUB(this, online);
		}

		public void DisconnectUSB()
		{
			try
			{
				stopRecThread_b = true;
				ChangeOnlineStateECUA(false);
				ChangeOnlineStateECUA(false);
				ECUReceiveConnect(false);
				if (!rOpened_b)
				{
					return;
				}
				try
				{
					if (PCANBasic.Uninitialize(m_PcanHandle) != TPCANStatus.PCAN_ERROR_OK)
					{
						rqu_Errors.Enqueue("CAN\tFailed to close");
					}
					rOpened_b = false;
					if (m_ReadThread != null)
					{
						m_ReadThread.Abort();
						m_ReadThread.Join();
						m_ReadThread = null;
					}
				}
				catch (Exception ex)
				{
					rqu_Errors.Enqueue("CAN\tFailed to close: " + ex.Message);
				}
			}
			catch
			{
			}
		}

		public CANMessage AddMessage(CANMessage Message)
		{
			try
			{
				if (!rHashMessages_ht.Contains(Message.ID))
				{
					Message.MessageSend += SendMessage;
					rHashMessages_ht.Add(Message.ID, Message);
				}
				return Message;
			}
			catch
			{
				return null;
			}
		}

		public CANMessage GetMessage(int id)
		{
			if (rHashMessages_ht.ContainsKey(id))
			{
				return (CANMessage)rHashMessages_ht[id];
			}
			return null;
		}

		private void SendMessage(object msg)
		{
			CANMessage cANMessage = (CANMessage)msg;
			TPCANStatus tPCANStatus = TPCANStatus.PCAN_ERROR_OK;
			TPCANMsg MessageBuffer = cANMessage.Msg;
			cANMessage.SendTimestamp = (uint)(Environment.TickCount * 1000);
			try
			{
				tPCANStatus = PCANBasic.Write(m_PcanHandle, ref MessageBuffer);
			}
			catch
			{
				rqu_Errors.Enqueue("Send error for message " + cANMessage.Name);
				return;
			}
			if (tPCANStatus == TPCANStatus.PCAN_ERROR_OK)
			{
				cANMessage.Sent = true;
			}
			else
			{
				rqu_Errors.Enqueue("Send error for message " + cANMessage.Name);
			}
		}

		public void ECUReceiveConnect(bool cnct)
		{
			ECUReceiveConnected = cnct;
		}

		private void ReadFromHWBuffer()
		{
			TPCANStatus tPCANStatus = TPCANStatus.PCAN_ERROR_OK;
			Queue<CANMessage> queue = new Queue<CANMessage>();
			try
			{
				while (tPCANStatus == TPCANStatus.PCAN_ERROR_OK)
				{
					TPCANMsg MessageBuffer;
					TPCANTimestamp TimestampBuffer;
					tPCANStatus = PCANBasic.Read(m_PcanHandle, out MessageBuffer, out TimestampBuffer);
					if (tPCANStatus == TPCANStatus.PCAN_ERROR_OK && ECUReceiveConnected)
					{
						CANMessage item = new CANMessage(ref MessageBuffer);
						queue.Enqueue(item);
					}
				}
				while (queue.Count > 0)
				{
					CANMessage lMessage = queue.Dequeue();
					if (rHashMessages_ht.ContainsKey(lMessage.ID))
					{
						CANMessage cANMessage = (CANMessage)rHashMessages_ht[lMessage.ID];
						cANMessage.UpDateTPCANMsg(ref lMessage);
						cANMessage.Received = true;
					}
				}
			}
			catch
			{
			}
		}

		private void CANReadThreadFunc()
		{
			while (!stopRecThread_b)
			{
				if (m_ReceiveEvent.WaitOne(3))
				{
					ReadFromHWBuffer();
				}
			}
		}

		public int CheckDongleCode(uint code)
		{
			int result = 0;
			ulong num = 20080602uL;
			num <<= 32;
			num |= code;
			if (ConnectUSB() && PCANBasic.SetValue(m_PcanHandle, (TPCANParameter)128, ref num, 8u) == TPCANStatus.PCAN_ERROR_OK)
			{
				result = 1;
			}
			return result;
		}

		public void Dispose()
		{
			DisconnectUSB();
		}
	}
}
